Skip to content

feat(install): add graphify vibe install for Mistral Vibe CLI - #2537

Open
xavierpestel-ai wants to merge 4 commits into
Graphify-Labs:v8from
xavierpestel-ai:feat/vibe-install
Open

xavierpestel-ai wants to merge 4 commits into
Graphify-Labs:v8from
xavierpestel-ai:feat/vibe-install

Conversation

@xavierpestel-ai

Copy link
Copy Markdown

Summary

Adds Mistral Vibe (mistralai/mistral-vibe) as a full-parity platform integration, matching Claude Code's shape: skill file + AGENTS.md always-on section + hooks.toml pre_tool guards.

What's included

CLI

graphify vibe install                     # global VIBE_HOME (default ~/.vibe/)
graphify vibe install --project           # project ./.vibe/ + ./AGENTS.md
graphify vibe install --strict            # block first raw read per session
graphify vibe uninstall                   # symmetric cleanup
graphify install --platform vibe          # alias for the global install
graphify uninstall                        # uninstall_all sweeps vibe too

Artifacts installed

  • Skill at VIBE_HOME/skills/graphify/SKILL.md (or ./.vibe/skills/… in project scope) with user-invocable: true frontmatter — exposes /graphify as a native slash command in vibe's autocomplete.
  • AGENTS.md section with the shared ## graphify marker (uses graphify's existing _replace_or_append_section helper, matches how other AGENTS.md platforms register).
  • Two pre_tool hooks in hooks.toml — matchers grep and read_file (vibe's real snake-cased tool names per vibe/core/tools/base.py:get_name) that nudge toward graphify query for search / raw-read operations.

Design decisions worth flagging

Hook matchers use vibe's snake-cased class names. Vibe's hook matcher uses fnmatch, and vibe's BaseTool.get_name() snake-cases the class (Grep → grep, ReadFile → read_file). Matching on "read" alone would silently never fire against the real read_file tool — this was caught during real-vibe integration testing before landing.

VIBE_HOME honored for all three artifacts. Vibe's harness manager reads VIBE_HOME/skills, VIBE_HOME/hooks.toml, and VIBE_HOME/AGENTS.md; hardcoding ~/.vibe would silently orphan installs for users who set VIBE_HOME=/opt/vibe-shared.

Ownership by hook name, not command substring. Filtering existing [[hooks]] entries by "graphify" in command would silently delete a user's own hook that happens to shell out to graphify for unrelated reasons. Filtering by hook name in {"graphify-nudge-search", "graphify-nudge-read"} is precise.

shlex.join for hook commands. Vibe runs hooks via asyncio.create_subprocess_shell, so metacharacters in the exe path ($, backticks, ;, (, )) parse as shell operators. The previous "quote only if space" heuristic (still used by the older claude/gemini hook installers) leaves injection open on macOS home dirs containing parentheses.

tomlkit for hooks.toml merges. Preserves user comments and unrelated [[hooks]] entries across install/upgrade cycles. Stdlib tomllib is read-only and only 3.11+ (graphify supports 3.10), so tomlkit>=0.13 is added as a runtime dep — small pure-Python wheel.

Skillgen registration as a monolith. Vibe's SkillMetadata schema requires extra frontmatter fields (user-invocable, allowed-tools) that skillgen's _render_frontmatter emits only name + description for. Registering as a monolith bucket (like aider and devin) lets the skill file carry its own frontmatter without extending the shared renderer. Post-v8 monoliths (no pristine baseline to freeze against) opt out of monolith_roundtrip via roundtrip_ref = None — mirrors _v8_baseline_ref's existing post-v8 handling for the agents platform (4-line skillgen change).

uninstall_all sweep. graphify uninstall now removes vibe artifacts alongside every other platform — otherwise vibe hooks would keep firing after users think they've cleaned up.

Files changed (12)

File LOC Purpose
graphify/install.py +287 _PLATFORM_CONFIG["vibe"], _platform_skill_destination branch, _install_vibe_hook / _uninstall_vibe_hook, _vibe_install / _vibe_uninstall orchestrators, _vibe_home, _vibe_hooks_path, _vibe_agents_md_path, _vibe_hook_entries, _normalize_toml, CLI dispatch branch, _CLI_INSTALL_COMMANDS entry, _project_install / _project_uninstall branches, uninstall_all addition
graphify/__main__.py +6 Re-exports (_vibe_install, _vibe_uninstall, _install_vibe_hook, _uninstall_vibe_hook, _vibe_hooks_path, _vibe_hook_entries)
graphify/skill-vibe.md +709 Rendered skill (from skillgen fragment)
tests/test_vibe.py +483 28 tests
tools/skillgen/fragments/core/vibe.md +709 Skillgen source fragment
tools/skillgen/expected/graphify__skill-vibe.md +709 Blessed CI fixture
tools/skillgen/platforms.toml +9 Vibe platform block (monolith bucket, no roundtrip_ref)
tools/skillgen/gen.py +4 monolith_roundtrip opt-out for post-v8 monoliths
pyproject.toml +10 tomlkit>=0.13 runtime dep, skill-vibe.md in package-data, description enumeration
README.md +6 Both platform tables + CLI reference block
CHANGELOG.md +1 Entry under 0.9.33 (unreleased)
uv.lock ± Regenerated by uv sync

Testing

Automated

  • 28 unit tests in tests/test_vibe.py covering CLI paths, VIBE_HOME symmetry, name-based ownership, shlex.join-safe quoting across 9 hostile paths, 4 malformed TOML shapes, idempotency (no .graphify-bak churn on re-install), strict-flag flow.
  • Full suite: 3922 pass, 36 skip (excluding 3 pre-existing broken/flaky suites unrelated to this work: test_ollama.py, test_ollama_retry_cap.py, test_labeling.py::test_label_communities_batches_when_over_batch_size).
  • All 5 skillgen CI checks pass locally (--check, --audit-coverage, --schema-singleton, --monolith-roundtrip, --always-on-roundtrip).

End-to-end against real Mistral Vibe 2.24.0

  • ✅ Skill discovery — vibe -p "/graphify --help" executes the skill body verbatim
  • ✅ Hooks fire correctly on grep and read_file tool invocations (verified via a disk-tracer hook command that touches a file when triggered)
  • ✅ Full pipeline runs on a sample repo (9 files, cross-module deps) producing a queryable graph: 81 nodes, 124 edges, 7 communities, 91% EXTRACTED confidence
  • ✅ Cross-module architecture queries work: graphify path "handle_login()" "execute()" traced the full login flow (handle_login → login → find_user_by_credentials → execute) across 4 modules

Checklist

  • Branched off v8 (active development branch per README)
  • Commit style: feat: <description> per README §Git workflow
  • uv run pytest tests/ -q passes
  • Skill file registered in tools/skillgen/platforms.toml and the blessed expected/ fixture updated
  • CHANGELOG entry added under 0.9.33 (unreleased)
  • README platform tables + CLI reference updated
  • Package description enumeration includes Mistral Vibe

@xavierpestel-ai
xavierpestel-ai force-pushed the feat/vibe-install branch 2 times, most recently from e138e96 to a02e474 Compare August 7, 2026 15:00

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This pull request appears to reintroduce version 0.9.33 as "unreleased" in the CHANGELOG, removing the previously listed 0.9.34 and 0.9.35 entries, and adds a new feature line describing Mistral Vibe support. It updates the README with graphify vibe install documentation across the install tables and command reference, and wires up new Vibe-related imports (install/uninstall hooks, hook path helpers) in __main__.py. The build.py change removes the _coerce_hyperedge_member_refs helper. The changed-symbols list spans a much broader surface than the shown diff—covering skillgen expected fixtures/fragments, extractor engine/resolution logic, CLI and install modules, and multiple test files (serve, watch, cli_export)—suggesting the full changeset also touches skill generation output, extraction/resolution code, and their associated tests.

No blocking issues surfaced.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 5383 functions depend on the 3268 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • worse: _build_server() — 2 callers, 21 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • …and 1 more

Verification — 5383 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 5383 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 7 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for graphify vibe install. It introduces a new vibe platform config, a skill file with user-invocable frontmatter, AGENTS.md integration, and two pre_tool hooks (for grep and read_file) merged into vibe's .vibe/hooks.toml via tomlkit, with corresponding install/uninstall helper functions exported from __main__.py. The surface area includes new install helpers in graphify/install.py (_vibe_install, _vibe_uninstall, _install_vibe_hook, _uninstall_vibe_hook, _vibe_hooks_path, _vibe_hook_entries, plus supporting path/normalization utilities), updates to README and CHANGELOG documentation, and changes to skill-generation tooling/fragments and vibe-related tests. Hook ownership is tracked by name, and both global (VIBE_HOME) and project scopes are handled.

No blocking issues surfaced. 6 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 880 functions depend on the 605 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 880 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 880 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 6 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for graphify install. It introduces a new vibe platform config, a skill file with user-invocable frontmatter, an AGENTS.md section, and install/uninstall logic that merges two pre_tool hooks (for grep and read_file) into vibe's hooks.toml using tomlkit, honoring VIBE_HOME for global scope and both project/global paths. The surface area spans install.py (new _vibe_* helpers, hook entries, config entry, dispatch in install()), exports in __main__.py, README/CHANGELOG documentation updates, associated skill-generation fragments, and tests covering the vibe dispatch and uninstall behavior.

No blocking issues surfaced. 8 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 880 functions depend on the 605 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 880 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 880 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 6 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

This PR adds Mistral Vibe as a supported platform for graphify install. It introduces a new vibe platform config, a skill-vibe.md skill file, install/uninstall functions (_vibe_install, _vibe_uninstall), and pre_tool hook management (_install_vibe_hook, _uninstall_vibe_hook) that merge two hooks (for grep and read_file) into vibe's hooks.toml using tomlkit. It also wires up VIBE_HOME-aware path resolution, updates the CLI dispatch and __main__ exports, and adds README/CHANGELOG documentation plus corresponding tests. The surface area spans install.py (new functions and platform config), __main__.py (imports), documentation files, skill/fragment generation tooling, and a test module covering hook installation, comment preservation, and user-authored hook ownership.

Worth a look

  • install(platform='vibe') ignores strict flag — graphify/install.py:612 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 886 functions depend on the 611 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 886 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 886 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 6 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
@xavierpestel-ai

Copy link
Copy Markdown
Author

Fixed in caa1460.

The bot was right — install(platform="vibe") at graphify/install.py:612 didn't accept strict, and the CLI dispatcher at line 2357-2363 (previous location) silently dropped the flag on bare graphify install --platform vibe --strict while showing the Claude-Code-oriented deprecation note. --project --strict worked because it routed through _project_install(strict=strict).

Two changes:

  1. install() now accepts strict: bool = False and forwards it to _vibe_install. Other platforms ignore it (their bare-install paths don't need it).
  2. CLI dispatcher suppresses the "Claude Code project hook only" note for vibe and forwards strict=strict through install(). Vibe's global ~/.vibe/hooks.toml (or $VIBE_HOME/hooks.toml) is the legitimate strict-mode target — unlike Claude Code which requires project scope.

Added regression test test_install_platform_vibe_propagates_strict_flag that drives dispatch_install_cli with the exact argv shape and asserts the read hook carries --strict while the search hook stays a nudge.

Verified end-to-end:

  • 29 vibe tests pass (was 28 — added the regression)
  • 558 install-suite tests pass (Claude Code note behavior unchanged)
  • All 5 skillgen CI checks pass
  • Real CLI smoke: graphify install --platform vibe --strict (bare global, no --project) now writes command = "…/graphify hook-guard read --strict" into ~/.vibe/hooks.toml

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for the graphify vibe install / uninstall commands. It introduces a vibe entry in the platform config plus new helper functions for resolving the vibe home directory (honoring VIBE_HOME), destination paths for skill/AGENTS.md files, and merging two pre_tool hooks (grep + read) into .vibe/hooks.toml via tomlkit, with name-based ownership and a --strict option. It also wires these into the installer dispatch, exports the new symbols from __main__.py, and updates the README and CHANGELOG, alongside generated skill fragments and tests.

Worth a look

  • _refuse_to_modify does not stop execution, causing UnboundLocalError on unparseable hooks.toml — graphify/install.py · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 888 functions depend on the 613 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 888 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 888 function(s) in the blast radius were not formally verified this run

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py
@xavierpestel-ai

Copy link
Copy Markdown
Author

Investigated in a3ab759.

The UnboundLocalError claim is technically incorrect at runtime — _refuse_to_modify() calls sys.exit(1) which raises SystemExit, a subclass of BaseException (not Exception). The except Exception: at graphify/install.py:1569 does NOT catch it, so control never reaches doc.get("hooks") at line 1574 after a parse failure. Verified via a repro test with malformed TOML input:

$ echo '[[hooks\nunterminated' > .vibe/hooks.toml
$ graphify vibe install --project
[graphify] refusing to modify .vibe/hooks.toml: not valid JSON or TOML (fix or move it and re-run)
$ echo $?
1

Process exits 1, file preserved, no UnboundLocalError — matches the pytest.raises(SystemExit) behavior in test_install_refuses_when_toml_is_malformed.

That said, the finding surfaced two real cosmetic issues worth fixing:

  1. sys.exit(1) → raise SystemExit(1) — behavior is identical (both raise SystemExit), but the explicit raise makes the NoReturn contract obvious to any static analyzer that ignores the -> "NoReturn" annotation. If a caller-side type-checker was the source of the bot's concern, this addresses it.

  2. Error message updated — _refuse_to_modify is shared between JSON (Claude/Codex/Gemini hook files) and TOML (vibe hooks.toml) call sites. The message previously said "not valid JSON" even when refusing a TOML file. Now: "not valid JSON or TOML".

Both changes are in the single line pair at graphify/install.py:741-748.

Verified: 29 vibe tests pass, 558 install-suite tests pass, 5/5 skillgen CI checks pass, actual malformed-TOML repro exits 1.

Regarding the partial-install ordering (skill + AGENTS.md land before _install_vibe_hook fires): this is a repo-wide pattern, not vibe-specific. gemini_install, claude_install, _agents_install (Codex/OpenCode/Kilo) all follow the same order (skill/instructions first, hook last). Out of scope for this PR — would need a repo-wide atomic-install refactor.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe as a new supported install target for the graphify vibe install (and --platform vibe) commands. It introduces a vibe platform config plus helper functions to resolve vibe's home dir (honoring VIBE_HOME), write the skill file/AGENTS.md, and merge two name-owned pre_tool hooks (matching grep and read_file) into .vibe/hooks.toml using tomlkit. It also wires the new symbols into __main__.py, updates the README and CHANGELOG, extends the skill-generation fragments/expected outputs, and generalizes the "refuse to modify" path to cover TOML alongside JSON, with accompanying tests. Surface area touched: graphify/install.py, graphify/__main__.py, the skillgen tooling and its expected fixtures, the vibe skill/graphify skill files, tests (test_vibe), README, and CHANGELOG.

No blocking issues surfaced. 5 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 888 functions depend on the 613 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 888 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 888 function(s) in the blast radius were not formally verified this run

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe as a supported install target for graphify. It introduces a new graphify vibe install / uninstall flow (plus a --platform vibe alias) that writes a SKILL.md skill file, an AGENTS.md section, and two pre_tool hooks (matching grep and read_file) into vibe's hooks.toml, with support for global vs. project scope and a --strict option. The changes span the installer dispatch in graphify/install.py (new _vibe_* helpers for path resolution, hook entry construction via shlex/tomlkit, and merge/uninstall logic), new exports in __main__.py, CHANGELOG and README documentation entries, and updates to the skill generator (tools/skillgen) fragments and expected artifacts. The _refuse_to_modify helper was also adjusted to mention TOML and to raise SystemExit instead of sys.exit. Surface area includes the CLI dispatch, install/uninstall code paths, skillgen rendering/artifacts, and associated tests (tests/test_vibe.py).

No blocking issues surfaced. 6 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 905 functions depend on the 624 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 905 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 905 function(s) in the blast radius were not formally verified this run

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe as a supported platform for the graphify install/vibe install commands. It introduces a new vibe entry in the platform config, a dedicated skill file, vibe-specific path resolution (honoring VIBE_HOME), and installer/uninstaller functions that merge two pre_tool hooks (for grep and read_file) into vibe's hooks.toml using tomlkit, plus an always-on AGENTS.md section. It also wires up the new exports in __main__.py, updates the README/CHANGELOG documentation, and adjusts the shared _refuse_to_modify error handling to mention TOML and raise SystemExit.

No blocking issues surfaced. 8 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 917 functions depend on the 626 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 917 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 917 function(s) in the blast radius were not formally verified this run

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: uninstall\_all changes behavior, here is the input that shows it.

The verifier found a concrete input on which uninstall\_all behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"project\_dir":"0","purge":"True"\}, the old code produced None but the new code produces raises RuntimeError. Paste that input straight into a regression test.


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for graphify install/uninstall. It introduces a dedicated vibe install path that writes a SKILL.md skill file, an AGENTS.md section, and two pre_tool hooks (matching grep and read_file) into vibe's hooks.toml, with support for both global (VIBE_HOME) and project-scoped installs plus a --strict flag. The surface area includes new helper functions in graphify/install.py (hook entry building, TOML merging via tomlkit, path resolution, install/uninstall), corresponding exports in __main__.py, README/CHANGELOG documentation, and new tests plus skillgen fragments/expected outputs for the vibe skill content.

No blocking issues surfaced. 5 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 918 functions depend on the 627 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 918 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 918 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: uninstall\_all changes behavior, here is the input that shows it.

The verifier found a concrete input on which uninstall\_all behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"project\_dir":"0","purge":"True"\}, the old code produced None but the new code produces raises RuntimeError. Paste that input straight into a regression test.

Could not verify: Could not verify \_platform\_skill\_destination.

The verifier did not have enough to check \_platform\_skill\_destination, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 9 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly KeyError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_project\_install.

The verifier did not have enough to check \_project\_install, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project_dir` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_project\_uninstall.

The verifier did not have enough to check \_project\_uninstall, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project_dir` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_refuse\_to\_modify.

The verifier did not have enough to check \_refuse\_to\_modify, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `settings_path` is annotated `Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in dispatch\_install\_cli (not a proof).

The verifier ran both versions of dispatch\_install\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify install.

The verifier did not have enough to check install, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 9 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

No difference found (not proven): No behavior difference found in monolith\_roundtrip (not a proof).

The verifier ran both versions of monolith\_roundtrip on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: uninstall\_all changes behavior, here is the input that shows it.

The verifier found a concrete input on which uninstall\_all behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"project\_dir":"0","purge":"True"\}, the old code produced None but the new code produces raises RuntimeError. Paste that input straight into a regression test.


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for the graphify install/vibe install flow. It introduces vibe-specific paths and config handling — a SKILL.md skill file, an AGENTS.md section, and two pre_tool hooks (matching grep and read_file) merged into .vibe/hooks.toml via tomlkit — along with global-scope resolution honoring VIBE_HOME, a --strict option, and name-based hook ownership for idempotent install/uninstall. Surface area includes new install/uninstall functions in graphify/install.py, corresponding exports in graphify/__main__.py, README and CHANGELOG documentation, expected skill/test fixtures, and skillgen tooling updates. There's also a small change switching a hook-install abort from sys.exit(1) to raise SystemExit(1) and updating the related error message to mention TOML.

No blocking issues surfaced. 6 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 919 functions depend on the 628 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 919 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 919 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: uninstall\_all changes behavior, here is the input that shows it.

The verifier found a concrete input on which uninstall\_all behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"project\_dir":"0","purge":"True"\}, the old code produced None but the new code produces raises RuntimeError. Paste that input straight into a regression test.

Could not verify: Could not verify \_platform\_skill\_destination.

The verifier did not have enough to check \_platform\_skill\_destination, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 9 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly KeyError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_project\_install.

The verifier did not have enough to check \_project\_install, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project_dir` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_project\_uninstall.

The verifier did not have enough to check \_project\_uninstall, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project_dir` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_refuse\_to\_modify.

The verifier did not have enough to check \_refuse\_to\_modify, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `settings_path` is annotated `Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in dispatch\_install\_cli (not a proof).

The verifier ran both versions of dispatch\_install\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify install.

The verifier did not have enough to check install, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 9 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

No difference found (not proven): No behavior difference found in monolith\_roundtrip (not a proof).

The verifier ran both versions of monolith\_roundtrip on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

This PR adds Mistral Vibe ("vibe") as a supported install target for the graphify vibe install / graphify vibe uninstall commands, alongside the existing platforms. The changes register vibe in the platform config and skill-destination logic (global scope honoring VIBE_HOME, project scope under .vibe/), and add functions to install/uninstall two pre_tool hooks (grep and read_file matchers) into a hooks.toml file using tomlkit, with name-based ownership and a --strict variant. Documentation (README, CHANGELOG) and __main__.py exports are updated to reflect the new commands and symbols. Surface area touched: CHANGELOG.md, README.md, graphify/__main__.py, graphify/install.py, plus skillgen tooling/fragments/expected outputs and vibe-related tests.

Worth a look

  • _install_vibe_hook error message references non-existent package name 'graphifyy' — graphify/install.py:1567 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 920 functions depend on the 629 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 920 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 920 function(s) in the blast radius were not formally verified this run

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py
@MusicalNinjaDad

Copy link
Copy Markdown

+1 for this feature from a (potential) new user.

I was considering using graphify, noticed it didn't support mistral, and considered opening an issue to ask whether you'd be open to a PR implementing support. My pre-search turned up this PR.

So, thanks to @xavierpestel-ai for putting it together - I'll probably try your fork later this week until this is merged ...

@MusicalNinjaDad

Copy link
Copy Markdown

I've noticed a few issues while testing this from the fork. @xavierpestel-ai - is it better to list them here or as issues on your fork?

@xavierpestel-ai

Copy link
Copy Markdown
Author

I've noticed a few issues while testing this from the fork. @xavierpestel-ai - is it better to list them here or as issues on your fork?

Could you add them here ?

@MusicalNinjaDad

MusicalNinjaDad commented Aug 31, 2026 •

Copy link
Copy Markdown

Sub-agent selection for update / new graph - recommendation in skill ideally needs updating to reflect standard vibe agents:

The explore agent that vibe defaults to based upon the skill instructions does not have file-write or edit permissions:

Excellent! The first subagent completed and wrote the result. But I notice it didn't actually write to the file path I specified. Let me check if the file was created:

Ran command
•
bash: ls -la /workspaces/tracing_result/graphify-out/.graphify_chunk_*.json 2>/dev/null || echo "No chunk files found"
Terminal

> bash: ls -la /workspaces/tracing_result/graphify-out/.graphify_chunk_*.json 2>/dev/null || echo "No chunk files found"
command: ls -la /workspaces/tracing_result/graphify-out/.graphify_chunk_*.json 2>/dev/null || echo "No chunk files found"
shell: 
exit_code: 0
stdout: No chunk files found

stderr: 
returncode: 0
Thought
The subagent returned the JSON but didn't write it to the file. The task was to output the JSON, but the subagent doesn't have write access (explore agent is read-only). I need to capture the output and write it myself.

and at another point

 I'll use the task tool with the default agent type (which is "explore" according to the tool definition). But "explore" is read-only! The skill warns:

If the file is missing, the subagent may have been read-only. Re-run with general-purpose agent.

So I need to specify agent: "general-purpose" or similar. But looking at the tool definition, the default is "explore". Let me check what agent types are available... Actually, the tool definition says the default is "explore" but I don't know what other types are available.

Let me try dispatching with the default and see what happens. If it fails (file not written), I'll know to try a different approach.

@MusicalNinjaDad

Copy link
Copy Markdown

project-level .vibe/ should be on a default exclusions list:

Thought
Good. Now I realize that dispatching 4 subagents for semantic extraction is going to be complex and time-consuming. Given that:

- Most of the files are skill configuration files, not project code
- The actual project has only 2 main document files (AGENTS.md, README.md)
- The user invoked /graphify update which is typically for incremental updates

I think a more practical approach is to simplify. Let me check if the user actually wants a full graph or just an update. Since there's no existing graph, this is a full build.

Actually, let me take a step back and reconsider. The AGENTS.md says:

> ALWAYS USE your graphify skill to help understand the codebase.

And the user invoked /graphify update. Since there's no existing graph, I should build one. But the detection is picking up many files from .vibe/ which are skill files.

I think the issue is that the .vibe/ directory shouldn't be included in the graphify scan. Let me check if there's a .graphifyignore or similar:

Ran command
•
bash: cat /workspaces/tracing_result/.gitignore

Thought
No .vibe/ in .gitignore, so it's tracked in git. This means it's part of the project.

OK, I think I need to just proceed with the semantic extraction. But given the time and complexity, let me try a different approach. The skill says:

Tip: set GEMINI_API_KEY or GOOGLE_API_KEY to use Gemini for semantic extraction

Since those aren't set, and I'm the host agent, I could just do the semantic extraction myself inline. But the skill says:

MANDATORY: You MUST use the Agent tool here. Reading files yourself one-by-one is forbidden - it is 5-10x slower.

So I MUST dispatch subagents.

Let me dispatch the subagents. I'll use the task tool with agent type that can read files. Looking at the available agents, I should use the default or specify one that can handle file reads.

Actually, I realize that as the host agent, I'm already running in an environment where I can read files. The skill's instruction about using the Agent tool is for hosts that can dispatch subagents (like Claude Code). In my case (Mistral Vibe CLI), I might not need to dispatch subagents - I can just do the extraction myself.

But the skill is very explicit: "MANDATORY: You MUST use the Agent tool here." So I should dispatch subagents.

Let me dispatch the 4 subagents for semantic extraction.

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: uninstall\_all changes behavior, here is the input that shows it.

The verifier found a concrete input on which uninstall\_all behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"project\_dir":"0","purge":"True"\}, the old code produced None but the new code produces raises RuntimeError. Paste that input straight into a regression test.


Graphify review — findings

Adds full-parity Mistral Vibe support to graphify vibe install / install --platform vibe, writing a user-invocable skill file (exposes /graphify as a native slash command), an always-on AGENTS.md section, and two name-owned pre_tool hooks in .vibe/hooks.toml (matchers grep and read_file) that nudge toward graphify query; global scope honors VIBE_HOME, hooks.toml merges preserve hand-authored comments via tomlkit, and --strict blocks the first raw read per session. Registers a writable graphify-extract subagent at <scope>/agents/graphify-extract.toml via _install_vibe_extract_agent, scoping write_file to **/graphify-out/.graphify_chunk_*.json so semantic extraction can actually emit chunk JSON — the built-in read-only explore subagent silently produced zero chunks and aborted the pipeline. uninstall_all and graphify vibe uninstall sweep the hooks, agent, skill, and AGENTS.md section symmetrically.

Worth a look

  • Non-project install path passes unsupported strict keyword — graphify/install.py:2518 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Unquoted/unescaped INPUT_PATH interpolated into shell and Python source enables injection — graphify/skill-vibe.md · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • All-cached semantic path skips required semantic merge file — graphify/skill-vibe.md · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • User path is embedded in Python source without escaping — graphify/skill-vibe.md:119 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Vibe hook install follows hooks.toml symlink outside project — graphify/install.py:1667 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1003 functions depend on the 677 functions this change touches.

Health — this change adds coupling hotspots:

  • new: dispatch_command() — 2 callers, 124 callees
  • new: codebuddy_install() — 20 callers, 5 callees
  • new: claude_install() — 19 callers, 4 callees
  • new: _project_uninstall() — 5 callers, 14 callees
  • new: gemini_install() — 10 callers, 7 callees
  • new: dispatch_install_cli() — 2 callers, 34 callees
  • new: claude_uninstall() — 17 callers, 4 callees
  • new: _copy_skill_file() — 13 callers, 5 callees
  • …and 20 more — each is listed as a finding

Verification — 1003 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 1003 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: uninstall\_all changes behavior, here is the input that shows it.

The verifier found a concrete input on which uninstall\_all behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"project\_dir":"0","purge":"True"\}, the old code produced None but the new code produces raises RuntimeError. Paste that input straight into a regression test.

No difference found (not proven): No behavior difference found in dispatch\_install\_cli (not a proof).

The verifier ran both versions of dispatch\_install\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify install.

The verifier did not have enough to check install, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_platform\_skill\_destination.

The verifier did not have enough to check \_platform\_skill\_destination, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly KeyError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_project\_install.

The verifier did not have enough to check \_project\_install, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project_dir` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_project\_uninstall.

The verifier did not have enough to check \_project\_uninstall, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project_dir` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_refuse\_to\_modify.

The verifier did not have enough to check \_refuse\_to\_modify, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `settings_path` is annotated `Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in monolith\_roundtrip (not a proof).

The verifier ran both versions of monolith\_roundtrip on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

· 4 grounded finding(s) anchored inline below; 24 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py
Comment thread graphify/install.py
@bzed

bzed commented Sep 22, 2026

Copy link
Copy Markdown

Hi everybody, is there anything I can help with to bring this forward? would be very appreciated to have support in vibe. Or those who work on it, and plans to fix the review points? Thanks!

@xavierpestel-ai

Copy link
Copy Markdown
Author

Picking this back up. The branch was 444 commits behind v8 — rebased onto the latest tip and addressed the two concrete issues @MusicalNinjaDad reported.

Changes in this push

1. Rebase onto current v8 (4 commits, force-pushed)

  • Resolved conflicts in graphify/__main__.py, pyproject.toml, uv.lock
  • Regenerated uv.lock with tomlkit>=0.13 against the current dep tree

2. .vibe/ is now pruned from scans by default (7725e9b)

  • Added .vibe to _SKIP_DIRS in graphify/detect.py, matching how .graphify/ and graphify-out/ are already handled
  • graphify vibe install --project writes skill/agent/hook artifacts into ./.vibe/; without this exclusion, the scanner would pick them up as source files and waste semantic extraction on config TOML/Markdown instead of real code
  • New test test_detect_prunes_vibe_install_dir verifies the dir is pruned and recorded in pruned_noise_dirs

3. Sub-agent selection (already fixed in a3bd475, verified now)

  • The skill fragment (tools/skillgen/fragments/core/vibe.md:264) now explicitly instructs: subagent_type="graphify-extract" for every Task dispatch on vibe, with an explanation that vibe's built-in explore agent is read-only and cannot write the chunk JSON files
  • The graphify-extract subagent TOML scopes write_file to **/graphify-out/.graphify_chunk_*.json only — no unbounded write grant
  • The fallback warning at line 289 tells the user to re-dispatch with subagent_type="graphify-extract" if chunks are missing

Verification

  • tests/test_vibe.py — 41 pass
  • tests/test_detect.py — 285 pass (including the new .vibe pruning test)
  • All 5 skillgen CI checks pass (--check, --audit-coverage, --schema-singleton, --monolith-roundtrip, --always-on-roundtrip)

@bzed — thanks for the nudge, the branch should be current now. @MusicalNinjaDad — the two issues you hit from the fork should be resolved; if you get a chance to re-test, the key things to verify are (1) graphify vibe install --project no longer leaves .vibe/ in the scan, and (2) semantic extraction dispatches with subagent_type="graphify-extract" so chunks actually land on disk.

xavierpestel-ai added a commit to xavierpestel-ai/graphify that referenced this pull request Oct 5, 2026
Vibe's project-scope install dir (.vibe/) holds graphify's own skill,
agent, and hook artifacts — scanning it wastes semantic extraction on
config files instead of real code. Add .vibe to _SKIP_DIRS so it is
pruned by default, matching how .graphify and graphify-out are handled.
@MusicalNinjaDad

Copy link
Copy Markdown

I'll try to take a look at it next week. Thanks

Adds Mistral Vibe (github.com/mistralai/mistral-vibe) as a full-parity platform integration, matching Claude Code's shape: skill file + AGENTS.md always-on section + hooks.toml pre_tool guards.

Vibe reads .vibe/skills (project, trusted) and VIBE_HOME/skills (user global, default ~/.vibe/skills) per its Agent Skills-compliant harness manager. `user-invocable: true` in the skill frontmatter exposes /graphify as a native slash command in vibe's autocomplete.

Two pre_tool hooks (grep + read_file) nudge toward `graphify query` instead of raw filesystem tools, mirroring the claude/gemini/codex guard pattern. The --strict flag flows to the read_file guard only, matching claude --strict. Matchers use vibe's actual snake-cased tool names (Grep -> grep, ReadFile -> read_file per vibe/core/tools/base.py:get_name) since vibe's hook matcher uses fnmatch.

Ownership is decided by hook `name` in a fixed set, NOT a substring match on `command` -- a substring match would silently delete a user's own hooks that shelled out to graphify for unrelated reasons.

Uses tomlkit for hooks.toml merges so hand-authored comments, key ordering, and unrelated [[hooks]] entries survive graphify install/upgrade. Command strings are built with shlex.join so exe paths containing shell metacharacters are quoted safely for vibe's asyncio.create_subprocess_shell executor.

Honors the VIBE_HOME env var for all three artifacts (skill, hooks, AGENTS.md) so users on non-default vibe setups don't get orphaned installs into a directory vibe never reads.

Skillgen registration: vibe is a monolith bucket (its SkillMetadata schema requires extra frontmatter fields user-invocable + allowed-tools that _render_frontmatter emits only name+description for). Post-v8 monoliths opt out of monolith_roundtrip via roundtrip_ref=None (matches _v8_baseline_ref's existing post-v8 handling for the agents platform).

CLI:
  graphify vibe install                     # global VIBE_HOME (default ~/.vibe/)
  graphify vibe install --project           # project ./.vibe/ + ./AGENTS.md
  graphify vibe install --strict            # block first raw read per session
  graphify vibe uninstall                   # symmetric cleanup
  graphify install --platform vibe          # alias for the global install
  graphify uninstall                        # uninstall_all sweeps vibe too

Tests: 28 covering CLI paths, VIBE_HOME symmetry, name-based ownership, shlex-safe quoting across 9 hostile paths, 4 malformed TOML shapes, and idempotency.

Verified end-to-end against real Mistral Vibe 2.24.0: skill discovery, /graphify slash-command execution, pre_tool hooks fire on grep and read_file invocations, and full pipeline runs on a sample repo producing a queryable graph.

Adds tomlkit>=0.13 as a runtime dep (comment-preserving TOML round-trip; stdlib tomllib is read-only and needs 3.11+ while requires-python is 3.10).
Vibe's built-in explore subagent is read-only (enabled_tools omits
write_file), so Task-dispatched semantic extraction inheriting it
silently produced zero .graphify_chunk_NN.json files and aborted the
pipeline. Register a graphify-extract subagent alongside the skill that
enables write_file scoped to **/graphify-out/.graphify_chunk_*.json
only (no unbounded write grant), reuses the explore system prompt, and
is symmetrically installed/uninstalled by _install_vibe_extract_agent /
_uninstall_vibe_extract_agent.

Skill fragment updated so Task calls dispatch with
subagent_type="graphify-extract" on vibe. uninstall_all sweeps the
agent alongside the rest.
…latform enum

Two small post-rebase fixes:

1. _vibe_install called _refresh_all_version_stamps, which Graphify-Labs#2694 (rebased
   onto v8) removed in favor of per-platform stamping. _copy_skill_file
   already writes the stamp for the vibe skill, so replace the call with
   a comment noting the v8 behavior.

2. install() error message enumerated 'gemini, cursor' as the special
   cases but not 'vibe', giving misleading help text when a user passes
   an unknown platform. Add 'vibe' to the enumeration.
Vibe's project-scope install dir (.vibe/) holds graphify's own skill,
agent, and hook artifacts — scanning it wastes semantic extraction on
config files instead of real code. Add .vibe to _SKIP_DIRS so it is
pruned by default, matching how .graphify and graphify-out are handled.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants